#include "slice2D.h"
#include <stdlib.h>
#include <assert.h>
#include <iostream>
using namespace std;

slice2D::slice2D(void*data, int pixelByteSize, int dimY, int dimX)
: _data(data), _pixelByteSize(pixelByteSize), _dimY(dimY), _dimX(dimX)
{
	
}

slice2D::slice2D(int pixelByteSize, int dimY, int dimX)
:_pixelByteSize(pixelByteSize), _dimY(dimY), _dimX(dimX)
{
	_data = malloc(_pixelByteSize*dimY*dimX);
	memset(_data, 0, _pixelByteSize*dimY*dimX);
}

slice2D::~slice2D()
{
	if(_data)
		free(_data);
}

slice2D* slice2D::generateShrinkedSlice(int minX, int maxX, int minY, int maxY)
{
	slice2D* slice = new slice2D(_pixelByteSize, maxX-minX+1, maxY-minY+1);
	for(int i=minX; i<=maxX; i++)
		for(int j=minY; j<=maxY; j++)
			slice->setPixel(j-minY,i-minX, getPixel(j,i));
	return slice;
}



int slice2D::getDimX()
{
	return _dimX;
}
int slice2D::getDimY()
{
	return _dimY;
}

unsigned int slice2D::getPixel(int y, int x)
{
	//assert(y<_dimY);
	//assert(x<_dimX);
	if(x>=_dimX || y>=_dimY)
		return 0;
	unsigned int value = 0;
	if(_pixelByteSize==1)
		value = ((unsigned char*)(_data))[y*_dimX + x];
	else if(_pixelByteSize==2)
		value = ((unsigned short*)(_data))[y*_dimX + x];
	return value;
}

void slice2D::setPixel(int y, int x, unsigned int value)
{
	assert(y<_dimY);
	assert(x<_dimX);
	if(_pixelByteSize==1)
		((unsigned char*)(_data))[y*_dimX + x] = value;
	else if(_pixelByteSize==2)
		((unsigned short*)(_data))[y*_dimX + x] = value;
}


unsigned int slice2D::getPixel(double y, double x)
{
	unsigned int value = 0;

	return value;
}
unsigned int slice2D::getPixelNearest(double y, double x)
{
	unsigned int value = 0;
	return value;
}

unsigned int slice2D::getPixelBilinear(double y, double x)
{
	unsigned int value = 0;

	int j = (int)(y*(_dimY-1));
	int i = (int)(x*(_dimX-1));

	double fracX = x*(_dimX-1) - i;
	double fracY = y*(_dimY-1) - j;

	if ((fracX) == 0.0 && (fracY) == 0.0)
		return getPixel(j,    i);

	if( fracX == 0.0)
		return value = (unsigned int)(((double)getPixel(j,i)+(double)getPixel(j+1,i))*0.5);

	if( fracY == 0.0)
		return value = (unsigned int)(((double)getPixel(j,i)+(double)getPixel(j,i+1))*0.5);

	//if( fracX == 0.5 && fracY == 0.5)
	//	return 
/*	
	TL-TR
	 |      |
	BL-BR
*/
	double TL = (double)getPixel(j,    i);
	double TR = (double)getPixel(j,   i+1);
	double BL = (double)getPixel(j+1,i);
	double BR = (double)getPixel(j+1,i+1);

	value = (unsigned int)((TL*(1-fracX) + TR*fracX)*(1-fracY) + (BL*(1-fracX) + BR*fracX)*fracY);

	return value;
}

slice2D* slice2D::resize(double factor)
{
	int dimY = (int)(_dimY*factor);
	int dimX = (int)(_dimX*factor);

	slice2D* slice = new slice2D(1,dimY, dimX);
	for(int i=0; i<dimX; i++)
		for(int j=0; j<dimY; j++)
			slice->setPixel(j,i,this->getPixelBilinear(double(j)/double(_dimY),double(i)/double(_dimX)));
			//slice->setPixel(j,i,getPixel(j,i));
	return slice;
}

bool slice2D::writeToFile(const char* filename)
{
	FILE *pFile; 
	//fopen_s(&pFile, filename,"rb");
	pFile= fopen(filename, "wb");
	if (NULL == pFile) {
		cout<<"can't open file!"<<endl;
		return false;
	}

	int size = fwrite(_data, _pixelByteSize, _dimX*_dimY, pFile);
	if (size !=  _dimX*_dimY)
		return false;
	return true;
}

void slice2D::print()
{
	cout<<"Debug output: <<<<<<<<<"<<endl;
	for(int j=0; j<_dimY; j++)
	{
		for(int i=0; i<_dimX; i++)
		{
			cout<<this->getPixel(j,i)<<" ";
		}
		cout<<endl;
	}
}
